﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PACKETPARSERMAX20.CORE
{
    public abstract class DefinitionDefaultBase : ReadingBase 
    {
        public DefinitionContext context = null;

        public StringBuilder log = null;

        public DefinitionDefaultBase()
            : base()
        {
        }

        public DefinitionDefaultBase(DefinitionContext pContext)
            : base()
        {
            Initialize(pContext);
        }

        public void Initialize(DefinitionContext pContext)
        {
            //base.packet = pContext.Packet;
            //Reader = reader;
            //Core = core;
            //definedOpcodeList = pDefinedOpcodeList;
            context = pContext;
            base.Load(context.Data);
        }

        public int Index
        {
            get
            {
                return context.Reader.CurrentIndex;
            }
        }

        public bool ContainsOpcode(uint opcode)
        {
            return context.DefinedOpcodeList.Contains(opcode);
        }
 
        public Opcodes OpcodeEnum
        {
            get
            {
                return (Opcodes)Opcode;
            }
        }

        public uint Opcode
        {
            get
            {
                return context.Opcode;
            }
        }

        public string OpcodeName
        {
            get
            {
                return context.OpcodeName;
            }
        }

        public string Warning
        {
            get
            {
                return context.Warning;
            }

            set
            {
                context.Warning = value;
            }
        }

        public string Result
        {
            get
            {
                return context.Result;
            }

            set
            {
                context.Result = value;
            }
        }

        public int Direction
        {
            get
            {
                return context.Direction;
            }
        }

        public int ClientBuild
        {
            get
            {
                return context.ClientBuild;
            }
        }

        public MovementTransport ReadMovementTransport()
        {
            return ReadMovementTransport(ClientBuild, Opcode);
        }

        public string ClientBuildName
        {
            get
            {
                return context.ClientBuildName;
            }
        }

        public string AccountName
        {
            get
            {
                return context.AccountName;
            }
        }

        public WoWCore Core
        {
            get
            {
                return context.Core;
            }
        }

        public DefinitionBase GetDefinition()
        {
            return context.GetDefinition();
        }

        public DefinitionBase GetDefinition(uint opcode)
        {
            return context.GetDefinition(opcode);
        }

        public virtual bool Process()
        {
            return false;
        }

        public virtual bool Validate()
        {
            bool tresult = true;

            if (AvailableBytes > 0)
            {
                if (base.Stream.Position == 0)
                {
                    context.Warning = string.Format("{0} has not been defined.", OpcodeName);
                }

                context.Result = string.Format("has {0} bytes left.", AvailableBytes);
                tresult = false;
            }

            return tresult;
        }

        public virtual bool ValidateMovementOpcode(string pParentName, long pPosition, long pSize)
        {
            bool tresult = true;

            long left_over_size = CalcAvailableBytesCustom(pPosition, pSize);

            if (left_over_size > 0)
            {
                context.Result = string.Format("{0} has {1} bytes left.", OpcodeName, left_over_size);
                tresult = false;
            }

            return tresult;
        }

        public virtual bool ValidSize()
        {
            return base.Stream.Length < 50000;
        }

        public void UpdateObjectPosition(MovementInfo pMovementInfo)
        {
            Core.UpdateObjectPosition(pMovementInfo.guid, pMovementInfo, OpcodeName);
        }

        public void UpdateObjectPosition(ulong guid, float x, float y, float z, float o, uint time)
        {
            Core.UpdateObjectPosition(guid, x, y, z, o, time, OpcodeName);
        }

        public void UpdateObjectPosition(ulong guid, Coord3 coord3, float o, uint time)
        {
            Core.UpdateObjectPosition(guid, coord3.X, coord3.Y, coord3.Z, o, time, OpcodeName);
        }

        public void UpdateObjectPosition(ulong guid, Coord3 coord3, uint time)
        {
            Core.UpdateObjectPosition(guid, coord3.X, coord3.Y, coord3.Z, 0f, time, OpcodeName);
        }

        public void UpdateObjectPosition(ulong guid, Coord4 coord4, uint time)
        {
            Core.UpdateObjectPosition(guid, coord4.X, coord4.Y, coord4.Z, coord4.O, time, OpcodeName);
        }

        public string HexDump()
        {
            //StringBuilder sb = new StringBuilder();
            //sb.AppendLine("**********************************************************");
            //sb.AppendLine(string.Format("Index: {3}, Opcode: {0} {1},  Direction: {2}", Opcode, OpcodeName, Direction, Index));

            //sb.AppendLine(context.Data.ToHexDump(OpcodeName, Opcode, 0, context.Data.Length, Direction));
            //sb.AppendLine("**********************************************************");

            //return sb.ToString();


            StringBuilder hexDump = new StringBuilder();
            hexDump.AppendLine("**********************************************************");
            hexDump.AppendLine(string.Format("Index: {3}, Opcode: {0} {1},  Direction: {2}, Size: {0}", Opcode, OpcodeName, Direction, Index, context.Data.Length));
            hexDump.AppendLine("|------------------------------------------------|----------------|");
            hexDump.AppendLine("|00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F |0123456789ABCDEF|");
            hexDump.AppendLine("|------------------------------------------------|----------------|");
            int start = 0;
            int count = context.Data.Length;
            int end = start + count;
            for (int i = start; i < end; i += 16)
            {
                StringBuilder text = new StringBuilder();
                StringBuilder hex = new StringBuilder();
                hex.Append("|");

                for (int j = 0; j < 16; j++)
                {
                    if (j + i < end)
                    {
                        byte val = context.Data[j + i];
                        hex.Append(context.Data[j + i].ToString("X2"));
                        hex.Append(" ");
                        if (val >= 32 && val <= 127)
                        {
                            text.Append((char)val);
                        }
                        else
                        {
                            text.Append(".");
                        }
                    }
                    else
                    {
                        hex.Append("   ");
                        text.Append(" ");
                    }
                }
                hex.Append("|");
                hex.Append(text + "|");
                hex.AppendLine();
                hexDump.Append(hex.ToString());
            }

            hexDump.AppendLine("**********************************************************");

            return hexDump.ToString();
        }

        //public bool LogIt
        //{
        //    get
        //    {
        //        return context.Core.eventManager.LogIt;
        //    }
        //}
 
        //public void InitLog()
        //{
        //    //if (LogIt) log = new StringBuilder();
        //    //if (LogIt) log.AppendLine("**********************************************************");
        //    //if (LogIt) log.AppendLine(string.Format("Index: {3}, Opcode: {0} {1},  Direction: {2}", Opcode, OpcodeName, Direction, Index));
        //}

        //public void Log()
        //{
        //    if (log == null)
        //    {
        //        //if (LogIt) log = new StringBuilder();
        //        //if (LogIt) log.AppendLine("**********************************************************");
        //        //if (LogIt) log.AppendLine(string.Format("Index: {3}, Opcode: {0} {1},  Direction: {2}", Opcode, OpcodeName, Direction, Index));
        //        //if (LogIt) log.AppendLine("SKIPPED!!! LOG NOT SETUP!!!");
        //        //if (LogIt) log.AppendLine("**********************************************************");
        //        //if (LogIt) context.Core.eventManager.Log(log.ToString());
        //        return;
        //    }
        //    //if (LogIt) log.AppendLine("**********************************************************");
        //    //if (LogIt) context.Core.eventManager.Log(log.ToString());
        //    Warning = string.Format("{0} {1}", "logged!", Warning);
        //}

        //public void LogHex()
        //{
        //    //if (LogIt) log.Append(HexDump());

        //}

        //public void LogAppend(object pValue)
        //{
        //    //if (LogIt) log.Append(pValue.ToString());
        //}

        //public void LogAppend(string pValue)
        //{
        //    //if (LogIt) log.Append(pValue);
        //}
        //public void LogAppendLine(string pValue)
        //{
        //    //if (LogIt) log.AppendLine(pValue);
        //}

        //public void LogAppendLine(string pType, string pName, object pValue)
        //{
        //    //if (LogIt) LogAppendLine(pType, pName, pValue, "");
        //}

        //public void LogAppendLine(string pType, string pName, object pValue, int i)
        //{
        //    //if (LogIt) LogAppendLine(pType, pName, pValue, i, "");
        //}
        //public void LogAppendLine(string pType, string pName, object pValue, int i, string pDescription)
        //{
        //    //if (LogIt) log.AppendLine(string.Format("{0} {1} = {2} {3}", pType, pName, string.Format("{0}_{1}", pValue, i), pDescription));
        //}
        //public void LogAppendLine(string pType, string pName, object pValue, string pDescription)
        //{
        //    //if (LogIt) log.AppendLine(string.Format("{0} {1} = {2} {3}", pType, pName, pValue, pDescription));
        //}
        //public void LogAppendLine(string pType, string pName, object pValue, int i, string pDescription, string subvalue)
        //{
        //    //if (LogIt) //if (LogIt) LogAppendLine(pType, pName, string.Format("{0}_{1}", pValue, i), pDescription, subvalue);
        //}
        //public void LogAppendLine(string pType, string pName, object pValue, string pDescription, string subvalue)
        //{
        //    //if (LogIt) log.AppendLine(string.Format("{0} {1} = {2} {3}", pType, pName, pValue, pDescription));
        //    //if (LogIt) log.Append(subvalue);
        //}



        public string GetObjectTypeAndName(ulong guid)
        {
            string type = "";
            string name = "";
            WoWObjectBase obj = Core.GetObject(guid);
            if (obj != null)
            {
                type = obj.TypeID.ToString();

                if (obj.TypeID == TypeID.TYPEID_PLAYER)
                {
                    if (guid == Core.PlayerGUID)
                    {
                        type += "(Current)";
                    }
                    else
                    {
                        type += "(Other)";
                    }
                }

                name = obj.Name;
            }

            return string.Format("guid: {2}, Type: {0}, Name: {1}", type, name, guid);
        }

        //public void LogAppendLine(string pType, string pName, object pValue, int i, bool packedguid)
        //{
        //    //if (LogIt) LogAppendLine(pType, pName, pValue, i, "", packedguid);
        //}

        //public void LogAppendLine(string pType, string pName, object pValue, bool packedguid)
        //{
        //    //if (LogIt) LogAppendLine(pType, pName, pValue, "", packedguid);
        //}

        //public void LogAppendLine(string pType, string pName, object pValue, int i, string pDescription, bool packedguid)
        //{
        //    ////if (LogIt)  LogAppendLine(pType, pName, string.Format("{0}_{1}", pValue, i), pDescription, packedguid);

        //    //if (LogIt)
        //    {
        //        string desc = "";

        //        if (packedguid)
        //        {
        //            if (pDescription.Length == 0)
        //            {
        //                desc = string.Format(" {0}, ", "packedguid");
        //            }
        //            else
        //            {
        //                desc = string.Format(" {0}, {1}, ", "packedguid", pDescription);
        //            }
        //        }
        //        else
        //        {
        //            if (pDescription.Length > 0)
        //            {
        //                desc = string.Format(" {0}, ", pDescription);
        //            }
        //        }



        //        string fulldesc = string.Format("({0}{1})", pDescription, (GetObjectTypeAndName((ulong)pValue)));
        //        log.AppendLine(string.Format("{0} {1} = {2} {3}", pType, pName, string.Format("{0}_{1}", pValue, i), fulldesc));
        //    }
        //}

        //public void LogAppendLine(string pType, string pName, object pValue, string pDescription, bool packedguid)
        //{

        //    //if (LogIt)
        //    {
        //        string desc = "";

        //        if (packedguid)
        //        {
        //            if (pDescription.Length == 0)
        //            {
        //                desc = string.Format(" {0}, ", "packedguid");
        //            }
        //            else
        //            {
        //                desc = string.Format(" {0}, {1}, ", "packedguid", pDescription);
        //            }
        //        }
        //        else
        //        {
        //            if (pDescription.Length > 0)
        //            {
        //                desc = string.Format(" {0}, ", pDescription);
        //            }
        //        }



        //        string fulldesc = string.Format("({0}{1})", pDescription, (GetObjectTypeAndName((ulong)pValue)));
        //        log.AppendLine(string.Format("{0} {1} = {2} {3}", pType, pName, pValue, fulldesc));
        //    }
        //}

        public byte ReadByte(string fieldname)
        {
            var temp = Reader.ReadByte();
            Result += "\n" + fieldname + ": " + temp.ToString();
            return temp;
        }

        public decimal ReadDecimal(string fieldname)
        {
            var temp = Reader.ReadDecimal();
            Result += "\n" + fieldname + ": " + temp.ToString();
            return temp;
        }

        public double ReadDouble(string fieldname)
        {
            var temp = Reader.ReadDouble();
            Result += "\n" + fieldname + ": " + temp.ToString();
            return temp;
        }

        public short ReadInt16(string fieldname)
        {
            var temp = Reader.ReadInt16();
            Result += "\n" + fieldname + ": " + temp.ToString();
            return temp;
        }

        public int ReadInt32(string fieldname)
        {
            var temp = Reader.ReadInt32();
            Result += "\n" + fieldname + ": " + temp.ToString();
            return temp;
        }

        public uint ReadUInt(string fieldname)
        {
            var temp = Reader.ReadUInt32();
            Result += "\n" + fieldname + ": " + temp.ToString();
            return temp;
        }

        public int ReadInt(string fieldname)
        {
            var temp = Reader.ReadInt32();
            Result += "\n" + fieldname + ": " + temp.ToString();
            return temp;
        }

        public float ReadFloat(string fieldname)
        {
            var temp = Reader.ReadSingle();
            Result += "\n" + fieldname + ": " + temp.ToString();
            return temp;
        }

        public long ReadInt64(string fieldname)
        {
            var temp = Reader.ReadInt64();
            Result += "\n" + fieldname + ": " + temp.ToString();
            return temp;
        }

        public sbyte ReadSByte(string fieldname)
        {
            var temp = Reader.ReadSByte();
            Result += "\n" + fieldname + ": " + temp.ToString();
            return temp;
        }

        public float ReadSingle(string fieldname)
        {
            var temp = Reader.ReadSingle();
            Result += "\n" + fieldname + ": " + temp.ToString();
            return temp;
        }

        public ushort ReadUInt16(string fieldname)
        {
            var temp = Reader.ReadUInt16();
            Result += "\n" + fieldname + ": " + temp.ToString();
            return temp;
        }

        public uint ReadUInt32(string fieldname)
        {
            var temp = Reader.ReadUInt32();
            Result += "\n" + fieldname + ": " + temp.ToString();
            return temp;
        }

        public ulong ReadUInt64(string fieldname)
        {
            var temp = Reader.ReadUInt64();
            Result += "\n" + fieldname + ": " + temp.ToString();
            return temp;
        }

        public string ReadString(int pLen, string fieldname)
        {
            var temp = ReadString(pLen);
            Result += "\n" + fieldname + ": " + temp;
            return temp;
        }

        public string ReadString(string fieldname)
        {
            var temp = ReadString();
            Result += "\n" + fieldname + ": " + temp;
            return temp;
        }

        public UInt64 popGuid(string fieldname)
        {
            var temp = popGuid();
            Result += "\n" + fieldname + ": " + temp.ToString();
            return temp;
        }

        public Coord3 ReadCoord3(string xname, string yname, string zname)
        {
            var temp = Reader.ReadCoord3();
            Result += "\n" + temp.ToString(xname, yname, zname);
            return temp;
        }

        public Coord4 ReadCoord4(string xname, string yname, string zname, string oname)
        {
            var temp = Reader.ReadCoord4();
            Result += "\n" + temp.ToString(xname, yname, zname, oname);
            return temp;
        }

        public MovementJump ReadMovementJump(bool log)
        {
            var temp = ReadMovementJump();
            Result += "\n" + temp.ToString();
            return temp;
        }

        public MovementFall ReadMovementFall(bool log)
        {
            return Reader.ReadMovementFall();
        }

        public MovementTransport ReadMovementTransport(int clientbuild, uint opcode, bool log)
        {
            return Reader.ReadMovementTransport(clientbuild, opcode);
        }
    }
}
